#include "camera_manager.h"
#include "smartbox.h"
#include "camera/hiknet/hiknet.h"

using namespace std::chrono; 

namespace app {

CameraManager::~CameraManager() {
  spdlog::get("logger")->info("CameraManager::~CameraManager");

  if (cam != nullptr) {
    delete cam;
    cam = nullptr;
  }
}

CameraManager::CameraManager(SmartBox* box, CameraGroup* cam_group, 
                              LogInfo* log_info):
                              cam(nullptr),
                              box(box),
                              cam_grp(cam_group),
                              prev_time(0),
                              log_ifo(log_info),
                              stop_status(0){
  spdlog::get("logger")->info("CameraManager::CameraManager");

  // 首先获取 rtspAddress
  if (!cam_grp->cam_ifo.rtspAddress.empty()) {
    // 调试时使用指定的rtspAddress
    api_addCamera(cam_grp->cam_ifo, box->cfg_ifo->mediaKitInfo, "0", "rtspMain", 1, log_ifo, 1);
  } else if (box->cfg_ifo->mediaKitInfo.ok) {
    api_addCamera(cam_grp->cam_ifo, box->cfg_ifo->mediaKitInfo, "1", "rtspMain", 0, log_ifo, 1);
    // 主动添加子码流
    std::string rtsp_sub = boost::algorithm::replace_last_copy(cam_grp->cam_ifo.rtspAddress, "/1", "/2");
    spdlog::get("logger")->info("CameraManager::CameraManager rtsp_sub: {} ", rtsp_sub);
    cv::VideoCapture reader = cv::VideoCapture(rtsp_sub);
    if (reader.isOpened()) { reader.release(); }
    // cam_grp->cam_ifo.rtspAddress = "rtsp://"+cam_grp->cam_ifo.user+":"+cam_grp->cam_ifo.passwd+"@"+cam_grp->cam_ifo.cameraIp+":554/ISAPI/streaming/channels/101";
  } else {

  }
  cam = new camera::HikNetwork(cam_grp, log_ifo, box->cfg_ifo);
}

int CameraManager::stop() {
  cam->stop_grab_img();

  stop_status = 1;
  while (stop_status != 0) {
    spdlog::get("logger")->info("CameraManager::stop stop_status: {} ", stop_status);
    std::this_thread::sleep_for(milliseconds(200));
  }
  return 0;
}

int CameraManager::run() {
  return run_imp();
}

int CameraManager::run_imp() {
  int ret = 0;
  std::thread(&HikBase::start_grab_img, cam).detach();

  Json::Value root;
  root["smartboxId"] = box->cfg_ifo->smartboxId;
  root["cameraId"] = cam_grp->cam_ifo.cameraId;
  
  int64 upload_time=0,start_time=0, cur_time=0, check_sys_time=0, remove_time=0;
  remove_time = check_sys_time = start_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
  int upload_step = cam_grp->cam_ifo.delay_seconds;

  sewageStatus sewage_status;
  std::vector<RecSewageData> his_data;
  int rain_value = -1;
  int sleep_time = 15, img_cnt=0;
  while (true) {
    std::this_thread::sleep_for(milliseconds(sleep_time));
    if (stop_status == 1) {
      spdlog::get("logger")->info("CameraManager::run_imp stop_status == 1");
      break; 
    }

    // 循环删除图片
    if (cur_time - remove_time > 10 * 60 * 1e3) {
      remove_time = cur_time;
      std::string remove_dir = log_ifo->get_log_path("img");
      spdlog::get("logger")->info("remove_file remove_dir: {} ", remove_dir);
      remove_file(remove_dir, 1 * 60 * 60, ".jpg");
    }

    cv::Mat img;
    cam->get_img(img);
    if (img.empty()) {
      if (sleep_time > 300) { spdlog::get("logger")->info("CameraManager::run_imp {}: img.empty()...", cam_grp->cam_ifo.cameraIp);  }
      sleep_time += 15;
      continue; 
    } else { sleep_time = 15; }

    cur_time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
    // 假设服务器性能足够好 无限发
    if (cur_time - start_time < upload_step * 1e3) { continue; }
    // if (cur_time - start_time < 1000) { continue; }
    if (log_ifo->log_level_3) spdlog::get("logger")->info("upload_step: {} ", upload_step);

    // 定时上传图片
    start_time = cur_time;
    std::string img_path = log_ifo->get_log_path("img") + "/" + std::to_string(log_ifo->counter()) + "_upload.jpg";
    if (log_ifo->log_level_3) spdlog::get("logger")->info("img_path: {} ", img_path);
    cv::Mat save_img = img.clone();
    if (check_rect_in_img(cam_grp->cam_ifo.rec_region, img) == 0) {
      save_img = img(cam_grp->cam_ifo.rec_region).clone();
    }
    cv::imwrite(img_path, save_img);
    std::string file_url="";
    ret = post_file(file_url, box->cfg_ifo->httpServer, box->cfg_ifo->postAPI.uploadFile, img_path, "name", 2, 1, log_ifo);
    if (file_url.empty()) {
      // 再次尝试
      file_url = post_file(file_url, box->cfg_ifo->httpServer, box->cfg_ifo->postAPI.uploadFile, img_path, "name", 2, 1, log_ifo);
    }
    // 上传失败时 将不进行识别
    if (file_url.empty()) { 
      spdlog::get("logger")->info("CameraManager::run_imp upload file_url.empty\n");
      continue; 
    }

    rain_value = box->get_rain_value();
    root["imgName"] = file_url;
    root["imgCnt"] = img_cnt;
    root["rainValue"] = rain_value;
    root["postTime"] = std::to_string(cur_time);
    std::string ret_body, msg = root.toStyledString();
    if (log_ifo->log_level_3) spdlog::get("logger")->info("CameraManager::run_imp upload uri: {}, msg: \n{}\n", box->cfg_ifo->postAPI.imageDetect, msg);
    if (img_cnt > 5000) { img_cnt = 0;}

    ret = post_data_base(ret_body, msg, box->cfg_ifo->httpServer, box->cfg_ifo->postAPI.imageDetect, -1, 1, log_ifo);
    if (ret != 0) { continue; }
    
    his_data.push_back(RecSewageData(img_cnt, rain_value, cur_time));
    img_cnt++;

    Json::Value ret_json;
    ret = parse_json(ret_body, ret_json, false);
    
    // 更新下一次上传的时间
    // if (ret_json["data"].size() > 0) { upload_step = 1000 * ret_json["data"][0]["delaySeconds"].asInt(); }
    // if (ret_json.isMember("delaySeconds")) { upload_step = ret_json["delaySeconds"].asInt(); } 
    // else { upload_step += 2; }
    // 上传间隔必须不低于配置文件时间
    // if (upload_step < cam_grp->cam_ifo.delay_seconds) { upload_step = cam_grp->cam_ifo.delay_seconds;}

    // 由于前后端时间容易不统一，取消服务器计算时间
    // if (ret_json.isMember("postTime")) { upload_step -= std::stoll(ret_json["postTime"].asString()); }
    // if (log_ifo->log_all_text) spdlog::get("logger")->info("CameraManager::run_imp postTime: {}", std::stoll(ret_json["postTime"].asString()));

    if (!ret_json.isMember("data")) { spdlog::get("logger")->info("CameraManager::run_imp ERROR ret_json not have member data"); continue; }
    for (auto data : ret_json["data"]) {
      if (!data.isMember("imgCnt")) { continue;}
      int img_cnt = data["imgCnt"].asInt();
      int data_idx = -1;
      for (int hd_idx = 0; hd_idx < his_data.size(); hd_idx++) { if (his_data[hd_idx].img_cnt == img_cnt) { data_idx = hd_idx; break;} }
      if (data_idx < 0) { continue; }
      his_data[data_idx].is_rec = 1;
      if (data.isMember("boxes") && data["boxes"].size() > 0) {
        for (auto b : data["boxes"]) {
          sewageBox sbox;
          sbox.box = cv::Rect(b["x"].asInt(), b["y"].asInt(), b["w"].asInt(), b["h"].asInt());
          sbox.score = b["score"].asFloat();
          sbox.class_idx = b["classIdx"].asInt();
          his_data[data_idx].boxes.push_back(sbox);
        }
        // 判断是否属于排污
        for (auto& box : his_data[data_idx].boxes) {
          if (box.class_idx == sewage_water && box.score > 0.6 && his_data[data_idx].rain_value <= 0) { his_data[data_idx].is_sewage=1; break;}
          // if (box.score > 0.4 && his_data[data_idx].rain_value <= 0) { his_data[data_idx].is_sewage=1; break;}
        }
        std::string water_color = data["waterColor"].asString();
        if (!water_color.empty()) {sewage_status.colors.push_back(water_color);}
      }
    }

    // 分析结果
    if (his_data.size() >= 10) { analysis_data(his_data, sewage_status); }
    // 已经开始排污1分钟
    if (sewage_status.start == 1) {
      sewage_status.start = 2;
      PostInfo pi = PostInfo(sewage_status.start_time, sewage_status.start_time, sewage_status.start_time, "SewageDetector", 1, "", "发现排污", 0);
      pi.cam_grp = cam_grp;
      pi.eventId = sewage_status.event_id;
      box->add_post_info(pi, onlyPostText);

      PostInfo pi2 = PostInfo(sewage_status.start_time - 6*1000, sewage_status.start_time + 6*1000, sewage_status.start_time, "uploadVideo", 1, img_path, "1", 0);
      pi2.cam_grp = cam_grp;
      pi2.video_path = "";
      
      if (!sewage_status.colors.empty()) {pi2.video_path = find_mode(sewage_status.colors);}
      pi2.eventId = sewage_status.event_id;
      box->add_post_info(pi2, onlyPostVideo);
    }
    // 排污已经结束
    if (sewage_status.end == 1) {
      sewage_status.end = 2;
      PostInfo pi = PostInfo(sewage_status.end_time, sewage_status.end_time, sewage_status.end_time, "SewageDetector", 1, "", "结束排污", 0);
      pi.cam_grp = cam_grp;
      pi.eventId = sewage_status.event_id;
      box->add_post_info(pi, onlyPostText);

      PostInfo pi2 = PostInfo(sewage_status.end_time - 6*1000, sewage_status.end_time + 6*1000, sewage_status.end_time, "uploadVideo", 1, img_path, "3", 0);
      pi2.cam_grp = cam_grp;
      // 特殊存储
      pi2.video_path = "";
      if (!sewage_status.colors.empty()) {pi2.video_path = find_mode(sewage_status.colors);}
      pi2.eventId = sewage_status.event_id;
      box->add_post_info(pi2, onlyPostVideo);
    }
    if (sewage_status.start == 2 && sewage_status.end == 2) {
      sewage_status.clear();
      // his_data.clear();
    }
    update_op(cur_time, check_sys_time, upload_time, img);
  }
  
  stop_status = 0;
  return 0;
}

int CameraManager::analysis_data(std::vector<RecSewageData>& his_data, sewageStatus& sstatus) {
  std::string log_str = "";
  for (auto& hd : his_data) { 
    int flag = 0;
    for (auto& box : hd.boxes) {
      if (box.class_idx == sewage_water && box.score > 0.6 && hd.rain_value <= 0) {
        flag = 1; break;
      }
    }
    if (flag) { log_str += "1 ";}
    else {log_str += "0 ";}
  }
  spdlog::get("logger")->info("CameraManager::analysis_data his_data :\n{}\n", log_str);

  // 已经找到开始排污时间点 要找排污结束时间点
  if (sstatus.start) {
    // 取前5个计算
    // 5个里面有4个则认为排污结束
    int rec_num = 5;
    int cur_sum = 0;
    int hd_idx = 1;
    for (; hd_idx < std::min(rec_num+1, int(his_data.size())); hd_idx++) {
      if (!his_data[0].is_sewage) { break; }
      if (!his_data[hd_idx].is_rec) { break; }
      if (!his_data[hd_idx].is_sewage) { cur_sum++; }
    }
    // [ 0 0 0 0 1 0 0 0 0 1 0 1 1 1 0 1 1 1]
    // [ 0 0 0 0 1 0  0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 1 1 1]
    // [ 1 1 1 0 1 1 1 0 1 0 1  0 0 0 0 ]
    // 排污结束 连续 stop_num 个非排污即为结束
    if (cur_sum >= 3) {
      sstatus.end = 1;
      sstatus.end_time = his_data[0].time;
      spdlog::get("logger")->info("CameraManager::analysis_data sstatus.end_time :\n{}\n", his_data[0].time);
      
      // 删除结束片段 防止重复查找
      his_data.erase(his_data.begin(), his_data.begin()+hd_idx+1);
    }
  }
  // 未找到开始排污时间点
  else {
    // 5个里面有3个则认为排污
    // [ 0 0 0 0 1 1 0 1 1 1 0 1 1 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 1 1 1 0 1 1 1]
    int is_find = 0, cur_sum=0, sum_cnt=0, move_idx=0;
    int rec_num = 5;
    while (move_idx < his_data.size()) {
      if (!his_data[move_idx].is_rec) { break; }
      if (sum_cnt < rec_num) { 
        cur_sum += his_data[move_idx].is_sewage;
        sum_cnt++;
      }
      if (sum_cnt >= rec_num) {
        if (cur_sum >= 3) {
          is_find = 1; break;
        } else {
          sum_cnt--;
          cur_sum -= his_data[move_idx-rec_num+1].is_sewage;
        }
      }

      move_idx++;
    }
    int start_idx = -1;
    if (is_find) {
      start_idx = move_idx - rec_num+1;
      while (start_idx < move_idx) {
        if (his_data[start_idx].is_sewage) { break;}
        start_idx++;
      }
    }
    // 排污开始
    if (start_idx >= 0) {
      sstatus.start = 1;
      sstatus.event_id = box->cfg_ifo->smartboxId + "_" + cam_grp->cam_ifo.cameraId + "_" + std::to_string(his_data[start_idx].time);
      sstatus.start_time = his_data[start_idx].time;
      spdlog::get("logger")->info("CameraManager::analysis_data sstatus.start_time :\n{}\n", his_data[start_idx].time);
      
      // 删除开始片段 防止重复查找
      his_data.erase(his_data.begin(), his_data.begin()+move_idx);
    }


    // // 计算最大非排污数量 剩下的即为排污数量 
    // int max_idx = 0, max_sum = 0, cur_sum = 0;
    // for (int i = 0; i < his_data.size(); i++) {
    //   if (!his_data[i].is_rec) { cur_sum++; continue;}
    //   int tmp_value = cur_sum;
    //   for (auto& box : his_data[i].boxes) {
    //     if (box.class_idx == sewage_sewage && box.score > 0.6 && his_data[i].rain_value <= 0) { cur_sum--; break;}
    //   }
    //   if (tmp_value == cur_sum) { cur_sum++; }
    //   if (cur_sum > max_sum) { max_sum = cur_sum; max_idx = i; }
    // }
    // // 排污开始
    // if (his_data.size() - max_idx >= 3) {
    //   sstatus.start = 1;
    //   sstatus.event_id = box->cfg_ifo->smartboxId + "_" + cam_ifo.cameraId + "_" + std::to_string(his_data[max_idx].time);
    //   sstatus.start_time = his_data[max_idx].time;
    // }
  }

  int continuity_cnt = 0;
  for (auto& hd : his_data) { if (hd.is_rec) { continuity_cnt++;} else { break; } }
  if (his_data.size() > 30 && continuity_cnt > 15 ) { his_data.erase(his_data.begin());}
  if (log_ifo->log_level_2) { spdlog::get("logger")->info("CameraManager::analysis_data his_data:{}, continuity_cnt:{}", his_data.size(), continuity_cnt); }
  // 强制删除
  if (his_data.size() > 50) { his_data.erase(his_data.begin()); }
  return 0;
}

int CameraManager::update_op(int64 cur_time, int64& sys_time, int64& upload_time, cv::Mat& img) {
  // // 每小时更新相机时间
  // if (cur_time - sys_time > 60 * 60 * 1e3) {
  //   if (log_ifo->log_core_img) spdlog::get("logger")->info("cam->check_camera_time");
  //   sys_time = cur_time;
  //   check_camera_time(cam->cam_ip, cam->user, cam->password);
  // }
  
  // 每小时更新后台最新图片
  if (cur_time - upload_time > 1 * 60 * 60 * 1e3) {
    upload_time = cur_time;

    if (!img.empty()) {
      std::string save_path = log_ifo->get_log_path()+"/" + std::to_string(log_ifo->counter()) + "_uploadImg.jpg";
      cv::imwrite(save_path, img);
      
      PostInfo pi = PostInfo(cur_time, cur_time, cur_time, "uploadImg", 0, save_path, "", 0);
      pi.cam_grp = cam_grp;
      box->add_post_info(pi, onlyPostText);
    }
  }
  return 0;
}

}		// namespace smartbox
